/**
 * 
 */
package spl.manager;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import java.util.LinkedList;

import spl.utils.GlobalLogger;

/**
 * @author avikam
 *
 */
public class JobsContainer {
	
	public static class Job {
		public static final String PENDING = "Non-Submitted";
		public static final String SUBMITTED = "In Progress";
		public static final String FINISHED = "Finished";
		
		private String status;
		private int id;
		private File configuraionPath;
		private Representation parentRepresentation;
		private Representation destenyRepresentation;
		
		Job(int jobId, File jobConfigurationPath, Representation src, Representation out) {
			this.id = jobId;
			
			this.configuraionPath = jobConfigurationPath;
			this.parentRepresentation = src;
			this.destenyRepresentation = out;
			
			this.status = Job.PENDING;
		}
		
		/**
		 * @return status of the job
		 */
		public String getStatus() {
			return this.status;
		}
		
		/**
		 * @return job id
		 */
		public int getId() {
			return this.id;
		}
		
		/**
		 * Change job status to completed
		 */
		public void setCompleted() {
			this.status = Job.FINISHED;
		}
		
		/**
		 * Change job status to submitted
		 */
		public void setProcessing() {
			this.status = Job.SUBMITTED;
		}
		
		/**
		 * @return configuration file path
		 */
		public File getConfigurationPath() {
			return this.configuraionPath;
		}

		/**
		 * @return representation id
		 */
		public int getSrcRepId() {
			return this.parentRepresentation.getId();
		}

		/**
		 * @return representation id
		 */
		public int getDstRepId() {
			return this.destenyRepresentation.getId();
		}
		
		/**
		 * @return resource id of the job
		 */
		public int  getResId() {
			return this.parentRepresentation.getResId();
		}

		/**
		 * @return xml stream
		 */
		public FileInputStream getContent() {
			FileInputStream f;
			
			// File doesn't yet exist
			if (null == this.configuraionPath)
				return null;
			
			try {
				f = new FileInputStream(this.configuraionPath);
			} catch (FileNotFoundException e) {
				GlobalLogger.getLogger().warning("Couldn't find file " + this.configuraionPath.getName());
				return null;
			}
			
			return f;
		}

		/**
		 * @return file size
		 */
		public int getSize() {
			if (null == this.configuraionPath)
				return 0;
			
			return (int) this.configuraionPath.length();
		}
		
	}
	
	private ArrayList<Job> completedJobs;
	private ArrayList<Job> processedJobs;
	private LinkedList<Job> pendingJobs;
	
	private int totalJobs;
	
	/**
	 * C'tor - allocate stacks
	 */
	public JobsContainer() {
		this.completedJobs = new ArrayList<Job>();
		this.processedJobs = new ArrayList<Job>();
		this.pendingJobs = new LinkedList<Job>();
		
		this.totalJobs = 0;
		
	}
	
	/**
	 * @return all the jobs in one list
	 */
	public List<Job> getJobs() {
		ArrayList<Job> ret = new ArrayList<Job>();
		
		ret.addAll(this.completedJobs);
		ret.addAll(this.processedJobs);
		ret.addAll(this.pendingJobs);
		
		return ret;
	}
	
	/**
	 * Adds a new job.
	 * @param jobId new jobId
	 * @param tmpConfPath configuration file path
	 * @param srcRep representation source
	 * @param outRep where the output would be placed
	 * @return new job we added.
	 */
	public synchronized Job addJob(int jobId, File tmpConfPath, Representation srcRep, Representation outRep) {
		
		Job newJob = new Job(jobId, tmpConfPath, srcRep, outRep); 
		
		this.pendingJobs.add(newJob);
		
		return newJob;
		
	}
	
	/**
	 * Take one job from the pending queue and return it.
	 * The function will add the Job to the processed queue
	 * @return new job to work on.
	 */
	public synchronized Job submitJob() {
		try {
			Job toSubmit = this.pendingJobs.remove();
			
			toSubmit.setProcessing();
			this.processedJobs.add(toSubmit);
			
			return toSubmit;
			
		} catch (RuntimeException e) {
			GlobalLogger.getLogger().fine("Tried to pump a job from empty queue");
			return null;
		}
	}
	
	/**
	 * Return jobs amount
	 * @return counter of jobs
	 */
	public synchronized int getNextJobId() {
		return this.totalJobs++;
	}
    
    
    /**
	 * Removes a job from it's in-completed state and list to
     * the completed list and completed state.
	 * @return counter of jobs
	 */
	public synchronized void finishJob(Job j) {
		// search job and remove it
        this.processedJobs.remove(this.processedJobs.indexOf((j)));
        
        this.completedJobs.add(j);
        
        j.setCompleted();
	}
}
